package utils

import (
	"crypto/tls"
	"github.com/hashicorp/go-retryablehttp"
	"net"
	"net/http"
	"sync"
	"time"
)

const (
	ConnectTimeout = 10 * time.Second
	RequestTimeout = 30 * time.Second
)

// TODO 应该把这两个字典当作全局变量来用！！！
// 连接池字典
var clientMap = make(map[string]*retryablehttp.Client)

// 带证书认证的结构
var transportMap = make(map[string]*http.Transport)

// 加一个锁 防止多线程同时写入字典的情况
var muClient sync.Mutex

func GetHttpClient(tag string, config *tls.Config) *http.Client {
	muClient.Lock()
	defer muClient.Unlock()

	// 如果是一个带证书的请求，在这里处理
	if config != nil {
		if _, ok := transportMap[tag]; !ok {
			transportMap[tag] = NewTransport()
			transportMap[tag].TLSClientConfig = config
		}
		return &http.Client{
			Transport: transportMap[tag],
			Timeout:   RequestTimeout,
		}
	}

	if _, ok := clientMap[tag]; !ok {
		clientMap[tag] = NewRetryHttpClient()
	}
	return clientMap[tag].StandardClient()
}

// 带证书的transport构建
func NewTransport() *http.Transport {
	dialContext := (&net.Dialer{
		Timeout:   ConnectTimeout,
		KeepAlive: 30 * time.Second,
	}).DialContext

	return &http.Transport{
		Proxy:                 http.ProxyFromEnvironment,
		DialContext:           dialContext,
		MaxIdleConns:          100,
		MaxConnsPerHost:       25,
		IdleConnTimeout:       30 * time.Second,
		TLSHandshakeTimeout:   ConnectTimeout,
		ExpectContinueTimeout: 1 * time.Second,
	}
}

// 使用http连接池
func NewRetryHttpClient() *retryablehttp.Client {
	retryClient := retryablehttp.NewClient()
	retryClient.RetryMax = 10
	retryClient.Logger = nil
	return retryClient
}
